#pragma once
#include"../net.hpp"
#include<mutex>

// 管理客户端的rpc请求 对应的 方法
enum class ParameterType
{
    BOOL,
    INTEGRAL,
    NUMERIC,
    STRING,
    ARRAY,
    OBJECT
};

class CallDescription
{
public:
    using ptr = std::shared_ptr<CallDescription>;
    using func = std::function<void(const Json::Value& parameters, Json::Value& result)>;
    using parametersTV = std::vector<std::pair<std::string, ParameterType>>;
    CallDescription() {} 

    bool parameterCheck(const Json::Value& parameters)
    {
        for (auto& e : _parametersType)
        {
            if (parameters[e.first].isNull())
            {
                LOG_ERROR << "[" << _name << "] " << "参数字段不存在：" << e.first;
                return false;
            }

            bool tmp = false;
            switch (static_cast<int>(e.second))
            {
            case (int)ParameterType::ARRAY:
                tmp = parameters[e.first].isArray();
                break;
            
            case (int)ParameterType::BOOL:
                tmp = parameters[e.first].isBool();
                break;

            case (int)ParameterType::INTEGRAL:
                tmp = parameters[e.first].isIntegral();
                break;

            case (int)ParameterType::NUMERIC:
                tmp = parameters[e.first].isNumeric();
                break;

            case (int)ParameterType::OBJECT:
                tmp = parameters[e.first].isObject();
                break;

            case (int)ParameterType::STRING:
                tmp = parameters[e.first].isString();
                break;
            default:
                tmp = false;
                break;
            }

            if (!tmp)
            {
                LOG_ERROR << "[" << _name << "] " << "参数类型错误：" << e.first;
                return false;
            }
        }

        return true;
    }

    func getCall()
    {
        return _call;
    }

    void setCallName(const std::string& method) {_name = method;}
    void setParametersType(const parametersTV& vt) {_parametersType = vt;}
    void setCall(func cb) {_call = cb;}
    void setReType(ParameterType type) {_ret_type = type;}
    void setAddress(const std::pair<std::string, uint16_t>& addr) {_address = addr;}

    std::pair<std::string, int> getAddress() {return _address;}
    std::string getMethodName() {return _name;}

    bool check()
    {
        if (_name.empty()) {
            LOG_ERROR << "服务方法未设置";
            return false;
        }
        else if (_parametersType.empty()) {
            LOG_ERROR << "参数类型未设置";
            return false;
        }
        else if (_call == nullptr) {
            LOG_ERROR << "具体的方法回调未设置";
            return false;
        }
        else if (_address.first.empty()) {
            LOG_ERROR << "方法地址未设置";
            return false;
        }
        else
        {
            return true;
        }
    }

private:
    std::string _name;
    parametersTV _parametersType;
    func _call;
    ParameterType _ret_type;
    std::pair<std::string, uint16_t> _address;
};

class CallManager
{
public:
    using ptr = std::shared_ptr<CallManager>;
    using container = std::unordered_map<std::string, CallDescription::ptr>;
    CallManager() {}

    void add(const std::string& method, CallDescription::ptr des)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        _manager.insert({method, des});
    }

    void del(const std::string& method)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        _manager.erase(method);
    }

    CallDescription::ptr getDescription(const std::string& method)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        auto it = _manager.find(method);
        if (it == _manager.end())
        {
            return CallDescription::ptr(nullptr);
        }

        return it->second;
    }

private:
    // 向外提供注册接口
    std::mutex _mutex;
    container _manager;
};

class RpcRoute
{
public:
    using ptr = std::shared_ptr<RpcRoute>;
    RpcRoute() :_route(new CallManager) {}

    // 注册到 Dispatcher 的rpc请求回调
    void onRpcReauest(BaseConnection::ptr conn, RPCRequest::ptr msg, BaseProtocol::ptr protocol)
    {
        auto response = MessageFactory::create<RpcResponse>();
        response->setType(MSG_Type::RPC_RES);
        response->setId(msg->getId());
        Json::Value result;

        auto func_description = _route->getDescription(msg->getMethod());
        if (func_description)
        {
            // 对收到的请求参数做合规性检查
            Json::Value parameters = msg->getParameters();
            if (func_description->parameterCheck(parameters))
            {
                // 做业务处理
                auto func = func_description->getCall();
                if (func)
                {
                    func(parameters, result);
                    // 组织响应，发送到客户端
                    response->setRcode(RCode::OK);
                }
                else
                {
                    LOG_WARN << "此方法的回调逻辑为空：" << msg->getMethod();
                    response->setRcode(RCode::NOT_SET_Handler);
                }
            }
            else
            {
                LOG_WARN << "参数比对不一致：" << msg->getMethod();
                response->setRcode(RCode::CHECK_FAILED);
            }
        }
        else
        {
            LOG_WARN << "没有这个请求方法对应的处理描述：" << msg->getMethod();
            response->setRcode(RCode::NOT_FOUND_METHOD);
        }

        response->setResult(result);

        //序列化 + 发送
        std::string str = protocol->serialize(response);
        if (!str.empty())
        {
            conn->send(str);
            LOG_DEBUG << "发送成功：\n";
            LOG_ERROR << str;
        }
    }

    void setMethodToFunc(const std::string& method, CallDescription::ptr des)
    {
        _route->add(method, des);
    }

    void delMethodToFun(const std::string& method)
    {
        _route->del(method);
    }

private:
    CallManager::ptr _route;
};